Zusammenfassung
Die Play-Ransomware, auch bekannt als PlayCrypt, ist eine Ransomware, die erstmals im Juni 2022 auftauchte. Die Ransomware zielte auf Branchen wie das Gesundheitswesen und die Telekommunikation sowie auf ein breites Spektrum von Regionen wie Lateinamerika, Europa und Nordamerika ab. Die Play-Ransomware ist dafür bekannt, sich über kompromittierte gültige Konten oder durch Ausnutzen bestimmter Schwachstellen Zugriff auf Netzwerke zu verschaffen. Sobald es sich im Netzwerk befindet, nutzt es einen großen Pool bekannter Post-Exploitation-Tools, um seinen Angriff fortzusetzen. Tools wie Bloodhound, PsExec, Mimikatz und AdFind sind einige Beispiele für Tools, die zuvor bei Angriffen mit dieser Ransomware verwendet wurden.
Ein weiterer Aspekt, der die Malware berühmt macht, ist die Vielzahl an Anti-Analyse-Techniken, die sie in ihren Payloads verwendet, wie etwa der Missbrauch von SEH und die Verwendung von ROP zur Umleitung des Ausführungsflusses. Durch den Einsatz von Techniken zur Verlangsamung des Reverse-Engineering-Prozesses erschweren Bedrohungsakteure die Erkennung und Abwehr der Malware.
Bereits im Jahr 2022 veröffentlichten andere Forscher einen hervorragenden Blogbeitrag, in dem sie die Malware selbst und einige der von ihr verwendeten Anti-Analyse-Techniken analysierten. In diesem Blogbeitrag werfen wir erneut einen Blick auf die Anti-Analyse-Techniken der jüngsten Varianten der Play-Ransomware. Wir erklären, wie sie funktionieren und wie wir einige von ihnen mithilfe von Automatisierungsskripten besiegen können.
Renditeorientierte Programmierung (ROP)
Beim Reverse Engineering von Malware müssen wir zunächst sicherstellen, dass der Kontrollfluss nicht verschleiert wird, um die Malware richtig zu verstehen.
Um seinen Kontrollfluss zu verschleiern, verwendet die Play-Ransomware in ihrer Nutzlast häufig eine ROP-Technik. Dies geschieht durch den Aufruf von über hundert Funktionen, die den Wert oben auf dem Stapel patchen und dann den Ausführungsfluss dorthin umleiten. Bevor wir darüber sprechen, wie die Schadsoftware dies genau macht, schauen wir uns zunächst an, wie die Assembleranweisungen CALL und RET im Allgemeinen funktionieren.
Wenn ein CALL erfolgt (in diesem Fall genauer gesagt ein Near Call), schiebt der Prozessor den Wert des Befehlszeigerregisters (in diesem Fall EIP) in den Stapel und verzweigt dann zu der durch den Aufrufzieloperanden angegebenen Adresse, die in diesem Fall ein Offset relativ zum Befehlszeiger ist. Die Adresse im Befehlszeiger plus dieser Offset ergeben die Adresse der aufzurufenden Funktion.
Der RET-Befehl hingegen zeigt das Ende eines Funktionsaufrufs an. Dieser Befehl ist für die Übertragung des Programmkontrollflusses an die Adresse oben auf dem Stapel verantwortlich. Und ja, dies ist genau die Adresse, die ursprünglich durch den Aufrufbefehl gesendet wurde!
Unter Berücksichtigung des Gesagten wäre im Idealfall die hervorgehobene Adresse im Bild unten die nächste Anweisung, die nach einem Aufruf der Zielfunktion (sub_42a4b9) ausgeführt werden würde:

Wie die Malware die Funktionsweise der CALL- und RET-Anweisungen missbraucht, lässt sich im folgenden Bild beobachten:

Sobald die Funktion aufgerufen wird, wird die Adresse 0x42a4b4 in den Stapel geschoben, sodass ESP darauf zeigt. Die aufgerufene Funktion addiert dann den Wert 0xA zur von ESP angezeigten Adresse und kehrt anschließend mithilfe der RET-Anweisung zurück. Diese Vorgänge führen dazu, dass der Kontrollfluss zu 0x42a4be (0x42a4b4 + 0xa) statt zu 0x42a4b4 umgeleitet wird.
Durch die Anwendung dieser Technik macht die Schadsoftware nicht nur die statische Analyse komplexer, da der Programmfluss nicht trivial ist, sondern kann auch das Debuggen erschweren, denn wenn Sie diese Art von Funktion überspringen, können viele Dinge passieren, bevor die reguläre „nächste Anweisung“ ausgeführt wird.
Eine weitere Möglichkeit, mit der die Malware diese ROP-Technik implementiert, ist die Verwendung des im folgenden Code gezeigten Ansatzes, der bei Shellcodes sehr verbreitet ist. Der durch den Zieloperanden der Aufrufanweisung angegebene Offset ist Null, wodurch die Adresse der aufzurufenden Funktion genau der Adresse der nächsten Anweisung entspricht. Diese Adresse wird dann oben auf den Stapel gelegt und die restlichen Vorgänge sind genau dieselben wie im vorherigen Beispiel:

Um die Analyse der Play-Ransomware zu unterstützen, hat Netskope Threat Labs auf Grundlage früherer Arbeiten anderer Forscher ein Skript entwickelt, um die eingesetzte ROP-Verschleierung zu beheben.
Das Skript sucht nach möglichen ROP-Kandidaten, sammelt den Offset, der oben auf dem Stapel hinzugefügt werden soll, und patcht die Adressen, die die ROP-Aufrufe ausführen, mit einem absoluten Sprung, wobei das Ziel die zur Laufzeit berechnete geänderte Transferadresse ist.
Nachfolgend sehen Sie ein Beispiel dafür, wie die Malware-Nutzlast vor und nach der Skriptausführung aussehen würde:
Vor:

Nach:

Anti-Demontage
Eine Anti-Disassemblierungstechnik, mit der Analysten und Disassembler ausgetrickst werden, besteht darin, den Ausführungsfluss auf Ziele zu übertragen, die sich in der Mitte anderer gültiger Anweisungen befinden.
Nehmen wir als Beispiel den Funktionsaufruf bei 0x42a4af, der im obigen ROP-Abschnitt verwendet wird. Die Opcodes für diesen CALL-Befehl sind „E8 05 00 00 00“. Das Byte 0xE8 ist der Operationscode des CALL-Befehls selbst und die anderen 4 Bytes stellen den Zieloperanden dar (den Offset relativ zu EIP).
Wie wir bereits besprochen haben, wäre die Adresse der aufzurufenden Funktion der Wert von EIP (0x42a4b4) + der Offset (0x5), und das ergibt die Adresse 0x42a4b9. Dieser Wert fällt jedoch in das letzte Byte einer anderen gültigen Anweisung bei 0x42a4b5:

An der Ausführung ändert sich durch dieses Verhalten nichts, da der Prozessor die Anweisungen korrekt versteht. Allerdings kann es sein, dass ein Disassembler die Anweisungen nicht korrekt darstellt, je nachdem, welchen Ansatz er verwendet (z. B. linearer Sweep), was die statische Analyse etwas knifflig macht.
Das von uns zum Beheben der ROP-Aufrufe bereitgestellte Skript behandelt dieses Szenario auch für die ROP-Ziele. Wenn man bedenkt, dass wir einen JMP-Befehl zum Patchen der Aufrufe verwenden, zwingen wir letztendlich auch den Disassembler, den richtigen Ablauf zu verstehen.
Junk-Code
Obwohl es sich hierbei um eine sehr einfache Technik handelt, ist sie dennoch erwähnenswert, da sie die Analyse der Malware deutlich verlangsamen kann. Bei der Einfügungstechnik für Junk-/Garbage-Code handelt es sich genau um das, was der Name vermuten lässt: das Einfügen unnötiger Anweisungen in die Binärdatei.
Anders als bei den bisher vorgestellten Techniken lässt sich der Disassembler durch das Einfügen von Junk-Code nicht austricksen, es kann jedoch dazu führen, dass Zeit mit der Analyse unnötigen Codes verschwendet wird. Die Play-Ransomware verwendet dies recht häufig, insbesondere bei den Zielen für ROP-Aufrufe.

Strukturierte Ausnahmebehandlung (SEH)
Eine weitere von der Malware verwendete Anti-Analyse-Technik ist der Missbrauch eines Windows-Mechanismus namens „Strukturierte Ausnahmebehandlung“ , der zur Behandlung von Ausnahmen dient.
Im Windows-Betriebssystem hat jeder Thread eine Struktur namens Thread Environment Block (TEB). In einer x86-Umgebung befindet sich die Adresse von TEB im FS-Register und enthält für den Thread selbst nützliche Informationen und befindet sich im Prozessadressraum. Das erste Feld dieser Struktur ist eine weitere Struktur namens Thread Information Block (TIB) und das erste Element dieser Struktur enthält eine Liste sogenannter „Ausnahmeregistrierungsdatensätze“.
Jeder dieser Datensätze besteht aus einer Struktur, die zwei Werte enthält. Der erste ist ein Zeiger auf den „nächsten“ Datensatz in der Liste und der zweite ist ein Zeiger auf den Handler, der für die Behandlung der Ausnahme verantwortlich ist.
Einfach ausgedrückt wird beim Auftreten einer Ausnahme der letzte der Liste hinzugefügte Datensatz aufgerufen und entschieden, ob er die ausgelöste Ausnahme behandelt oder nicht. Wenn dies nicht der Fall ist, wird der nächste Handler in der Liste aufgerufen und so weiter, bis das Ende der Liste erreicht ist. In diesem Fall wird der Standard-Windows-Handler aufgerufen.
Play missbraucht diese Funktion, indem es seinen eigenen Ausnahmehandler in die Ausnahmebehandlungsliste einfügt und dann eine Ausnahme erzwingt. Im folgenden Beispiel enthält das EBX-Register die Adresse des Ausnahmehandlers der Malware. Sobald dieser als erstes Element der Liste eingefügt ist (die vier hervorgehobenen Anweisungen oben), setzt die Malware EAX auf Null und dividiert es durch Null, wodurch eine Ausnahme verursacht wird (die beiden hervorgehobenen Anweisungen unten):

Sobald die Ausnahme ausgelöst wird, wird der letzte registrierte Handler aufgerufen. Die Malware verwendet diesen ersten Handler, um sich zu registrieren und einen zweiten aufzurufen, indem sie eine zweite Ausnahme erzwingt, jetzt jedoch über die INT1-Anweisung, um eine Debug-Ausnahme zu generieren. Der zweite registrierte Handler ist für die weitere Ausführung der „normalen“ Malware verantwortlich.
Diese Technik kann beim Debuggen der Malware sehr lästig sein, da der Debugger die Ausführung beim Auftreten der Ausnahme stoppen würde, was uns dazu zwingt, den Ausnahmehandler zu finden und vorher sicherzustellen, dass wir die Kontrolle darüber haben.
Zeichenfolgenverschleierung
Alle von der Malware verwendeten relevanten Zeichenfolgen werden verschleiert, sodass es schwierig ist, relevante Zeichenfolgen statisch zu kennzeichnen. Um ihre Zeichenfolgen zur Laufzeit zu deobfuskieren, generiert die Malware einen 8-Byte-Schlüssel und verwendet ihn als Eingabe für den Deobfuskationsalgorithmus.
Der Algorithmus zur Schlüsselgenerierung ist recht einfach. Es empfängt einen fest codierten Startwert und führt einige grundlegende Rechenoperationen innerhalb einer Schleife aus. Der Schleifenzähler ist ebenfalls ein fest codierter Wert, der in den analysierten Samples sehr groß war (z. B. 0x20c87548).
Wir können die zum Generieren des Schlüssels verwendeten Operationen im folgenden Python-Ausschnitt vereinfachen:
x = Seed
y = 0
i = 0
solange i < Zähler:
a = (x * x) >> 32
b = (x * y) + (x * y)
wenn y:
y = (a + b) & 0xffffffff
sonst:
y = a
x = ((x * x) & 0xffffffff) + i
i += 1
Schlüssel = struct.pack("<2I", *[x, y])
Der zum Deobfuskieren der Zeichenfolgen verwendete Algorithmus umfasst einige weitere Schritte und einige andere Operationen wie AND, OR und NOT. Diese Operationen werden in der verschleierten Zeichenfolge selbst angewendet und der letzte Schritt der Deobfuskationsschleife besteht darin, eine mehrbyteige XOR-Operation unter Verwendung des zuvor generierten 8-Byte-Schlüssels anzuwenden. Die Vorgänge können im folgenden Python-Snippet vereinfacht werden:
i = 0
solange i < len(enc_str):
dec_str[i] = enc_str[i]
j = 0
solange j < 8:
v1 = (dec_str[i] >> j) & 1
v2 = (dec_str[i] >> (j + 1)) & 1
wenn v1 != v2:
wenn v1 == 0:
dec_str[i] = (dec_str[i] & ~(1 << (j + 1))) & 0xFF
sonst:
dec_str[i] = (dec_str[i] | (1 << (j + 1))) & 0xFF
wenn v2 == 0:
dec_str[i] = (dec_str[i] & ~(1 << j)) & 0xFF
sonst:
dec_str[i] = (dec_str[i] | (1 << j)) & 0xFF
j += 2
dec_str[i] = ~dec_str[i] & 0xFF
dec_str[i] = (dec_str[i] ^ key[i % len(key)]) & 0xFF
i += 1
Es ist erwähnenswert, dass die Algorithmen viele Junk-Operationen enthalten, die für die Deobfuskation selbst nicht erforderlich sind und in den präsentierten Snippets entfernt wurden.
Das Team von Netskope Threat Labs hat zwei Skripte erstellt, die den Deobfuskationsprozess unterstützen: eines zum automatischen Generieren des 8-Byte-Schlüssels und ein weiteres zum Entschlüsseln der Zeichenfolge.
API-Hashing
Die Malware nutzt die bekannte API-Hashing- Technik, um die Windows-API-Funktionen aufzulösen, die sie zur Laufzeit verwendet. Der verwendete Algorithmus ist derselbe wie der im Jahr 2022 gekennzeichnete Algorithmus xxHash32, wobei der Hash-Funktion derselbe Seed von 1 bereitgestellt wird.
Der xxHash32-Algorithmus lässt sich leicht an der Menge der Konstanten erkennen, die er in seinen Operationen verwendet:

Um die Hash-Funktionen noch weiter zu verschleiern, fügt die Malware den Hash-Ergebnissen bestimmte Konstanten hinzu oder entfernt sie davon. Der konstante Wert ist für jede Probe unterschiedlich. Nachfolgend sehen Sie ein Beispiel, bei dem die Malware dem Hash-Ergebnis den Wert 0x4f5dcad4 hinzugefügt hat:

Netskope-Erkennung
- Netskope Threat Protection
- Win32.Ransomware.Playde
- Netskope Advanced Threat Protection bietet proaktiven Schutz gegen diese Bedrohung.
- Gen.Malware.Detect.By.StHeur und Gen:Heur.Mint.Zard.55 weisen auf eine Probe hin, die mithilfe einer statischen Analyse erkannt wurde
- Gen.Detect.By.NSCloudSandbox.tr zeigt ein Sample an, das von unserer Cloud-Sandbox erkannt wurde.
Schlussfolgerungen
Wie wir in diesem Blogbeitrag sehen können, setzt die Play-Ransomware mehrere Anti-Analyse-Techniken ein, um ihre Analyse zu verlangsamen. Von der String-Verschleierung über ROP bis hin zum Einsatz von SEH-Hijacking aktualisieren Bedrohungsakteure häufig ihr Arsenal und erweitern ihre Techniken, um die Wirkung ihrer Angriffe noch zerstörerischer zu machen. Netskope Threat Labs wird die Entwicklung der Play-Ransomware und ihres TTP weiterhin verfolgen.
IOCs
Alle mit dieser Kampagne verbundenen IOCs, Skripte und Yara-Regeln finden Sie in unserem GitHub-Repository.